from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission, User
from django.db import models

import facebook

class FacebookProfile(models.Model):
  
  # The underlying user object
  user = models.OneToOneField(User)
  
  # The only data required to access the Facebook API
  access_token = models.CharField(max_length=255)

  # Additional data
  #   Nothing here yet...
  
  @property
  def fbid(self):
    return self.user.username
  
  
  def change_access_token(self, access_token):
    """Update the access token used to interact with the Facebook API for
    this user.
    Params:
      String, the new access code.
    """
    if self.access_token != access_token:
      self.access_token = access_token
      self.save()
      
      
  def get_friends(self):
    """Fetch a list of IDs of this user's Facebook friends.
    Returns:
      A list of ints, each an FBID.
    """
    graph = self.get_fb_graph()
    friends = graph.get_connections("me", "friends")
    return [int(x['id']) for x in friends['data']]
  
  
  def get_fb_graph(self):
    """Return a Graph API object to directly access the Facebook SDK.
    Returns: 
      A GraphAPI object.
    """
    return facebook.GraphAPI(self.access_token)
  
  
  def get_action_objects(self, action_class, object_class):
    """Lookup the objects this user has acted on in the Open Graph.
    Params:
      action_class: A subclass of OpenGraphAction.
      object_class: A subclass of OpenGraphObject.
    Returns:
      A QuerySet of object_class instances.
    """
    graph = self.get_fb_graph()
    response = graph.get_connections(
      "me", 
      "%s:%s" % (settings.FACEBOOK_APP_NAMESPACE, 
                 action_class().get_open_graph_action())
    )
    
    obj_urls = []
    obj_type = object_class().get_open_graph_type()
    for entry in response['data']:
      if entry['data'].has_key(obj_type):
        obj_urls.append(entry['data'][obj_type]['url'])
    return object_class.objects.get_for_open_graph_urls(obj_urls)
      
  
  def publish_action(self, action, object):
    """Publish an action to the Open Graph API for this user.
    Params:
      action: An instance of an OpenGraphAction subclass.
      object: An instance of an OpenGraphObject subclass.
    Returns:
      String, the ID of the newly created action.
    """
    graph = self.get_fb_graph()
    data = {
      object.get_open_graph_type(): object.get_open_graph_url()
    }
    response = graph.put_object(
      "me", 
      "%s:%s" % (settings.FACEBOOK_APP_NAMESPACE, action.get_open_graph_action()),
      data
    )
    return response.get("id")
  
  
  def refresh_profile(self):
    """Connect to the Facebook API to refresh this user's data.
    Params:
      access_token: String, token to access the Facebook API.
    Returns:
      The updated User object.
    """
    graph = self.get_fb_graph()
    profile = graph.get_object("me")
    if (self.fbid != profile['id']):
      raise Exception('ID Mismatch')
    
    needs_save = False
    if self.user.first_name != profile['first_name']:    
      self.user.first_name = profile['first_name']
      needs_save = True
    
    if self.user.last_name != profile['last_name']:
      self.user.last_name = profile['last_name']
      needs_save = True
    
    if needs_save:
      self.user.save()
      self.save()
    return self
  
  
  def refresh_permissions(self):
    """Connect to the Facebook API and refresh the permissions that this user
    has granted us to access their data and interact with Facebook.
    """
    graph = self.get_fb_graph()
    permissions = graph.get_connections("me", "permissions")
    permissions = permissions["data"][0]
    
    ct = ContentType.objects.get_for_model(self)
    fb_permissions = Permission.objects.filter(content_type=ct)
    
    for perm in fb_permissions:
      if permissions.has_key(perm.codename):
        self.user.user_permissions.add(perm)
      else:
        self.user.user_permissions.remove(perm)
    self.user.save()
  